package com.deductive.common.config.mybatis;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;
import org.postgresql.util.PGobject;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * MyBatis TypeHandler for PostgreSQL Geometry type
 * Handles conversion between JTS Geometry objects and PostgreSQL geometry columns
 */
public class GeometryTypeHandler extends BaseTypeHandler<Geometry> {

    private static final WKBReader wkbReader = new WKBReader();
    private static final WKBWriter wkbWriter = new WKBWriter(2, true); // 2D with SRID

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException {
        try {
            // Convert JTS Geometry to WKB hex string
            byte[] wkb = wkbWriter.write(parameter);
            String wkbHex = WKBWriter.toHex(wkb);
            
            // Create PostgreSQL geometry object
            PGobject pGobject = new PGobject();
            pGobject.setType("geometry");
            pGobject.setValue(wkbHex);
            
            ps.setObject(i, pGobject);
        } catch (Exception e) {
            throw new SQLException("Error converting Geometry to PostgreSQL geometry", e);
        }
    }

    @Override
    public Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return parseGeometry(rs.getObject(columnName));
    }

    @Override
    public Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return parseGeometry(rs.getObject(columnIndex));
    }

    @Override
    public Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return parseGeometry(cs.getObject(columnIndex));
    }

    private Geometry parseGeometry(Object object) throws SQLException {
        if (object == null) {
            return null;
        }

        try {
            if (object instanceof PGobject) {
                PGobject pGobject = (PGobject) object;
                String wkbHex = pGobject.getValue();
                if (wkbHex != null && !wkbHex.isEmpty()) {
                    byte[] wkb = WKBReader.hexToBytes(wkbHex);
                    return wkbReader.read(wkb);
                }
            } else if (object instanceof String) {
                // Handle hex string directly
                String wkbHex = (String) object;
                if (!wkbHex.isEmpty()) {
                    byte[] wkb = WKBReader.hexToBytes(wkbHex);
                    return wkbReader.read(wkb);
                }
            }
            return null;
        } catch (ParseException e) {
            throw new SQLException("Error parsing geometry from database", e);
        }
    }
}
